package com.laundry.user.network

import android.content.Context
import com.google.gson.GsonBuilder
import com.laundry.user.BuildConfig
import com.laundry.user.data.local.TokenManager
import okhttp3.*
import okhttp3.logging.HttpLoggingInterceptor
import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory
import java.io.File
import java.util.concurrent.TimeUnit
import javax.inject.Inject
import javax.inject.Singleton

@Singleton
class NetworkClient @Inject constructor(
    private val context: Context,
    private val tokenManager: TokenManager
) {
    
    private val gson = GsonBuilder()
        .setDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'")
        .create()
    
    private val okHttpClient: OkHttpClient by lazy {
        OkHttpClient.Builder()
            .connectTimeout(NetworkConfig.CONNECT_TIMEOUT, TimeUnit.SECONDS)
            .readTimeout(NetworkConfig.READ_TIMEOUT, TimeUnit.SECONDS)
            .writeTimeout(NetworkConfig.WRITE_TIMEOUT, TimeUnit.SECONDS)
            .cache(createCache())
            .addInterceptor(createAuthInterceptor())
            .addInterceptor(createHeaderInterceptor())
            .addInterceptor(createCacheInterceptor())
            .addNetworkInterceptor(createNetworkCacheInterceptor())
            .addInterceptor(createRetryInterceptor())
            .apply {
                if (BuildConfig.DEBUG) {
                    addInterceptor(createLoggingInterceptor())
                }
            }
            .build()
    }
    
    private val retrofit: Retrofit by lazy {
        Retrofit.Builder()
            .baseUrl(ApiConfig.CURRENT_BASE_URL)
            .client(okHttpClient)
            .addConverterFactory(GsonConverterFactory.create(gson))
            .build()
    }
    
    val apiService: ApiService by lazy {
        retrofit.create(ApiService::class.java)
    }
    
    private fun createCache(): Cache {
        val cacheDir = File(context.cacheDir, "http_cache")
        return Cache(cacheDir, NetworkConfig.CACHE_SIZE)
    }
    
    private fun createAuthInterceptor(): Interceptor {
        return Interceptor { chain ->
            val originalRequest = chain.request()
            val token = tokenManager.getAccessToken()
            
            val newRequest = if (token != null) {
                originalRequest.newBuilder()
                    .header(ApiConfig.Headers.AUTHORIZATION, "Bearer $token")
                    .build()
            } else {
                originalRequest
            }
            
            val response = chain.proceed(newRequest)
            
            // 处理401未授权响应
            if (response.code == ApiConfig.StatusCode.UNAUTHORIZED) {
                response.close()
                
                // 尝试刷新token
                val refreshToken = tokenManager.getRefreshToken()
                if (refreshToken != null) {
                    val refreshResponse = refreshTokenSync(refreshToken)
                    if (refreshResponse != null) {
                        tokenManager.saveTokens(
                            refreshResponse.accessToken,
                            refreshResponse.refreshToken
                        )
                        
                        // 重新发送原始请求
                        val retryRequest = originalRequest.newBuilder()
                            .header(ApiConfig.Headers.AUTHORIZATION, "Bearer ${refreshResponse.accessToken}")
                            .build()
                        return@Interceptor chain.proceed(retryRequest)
                    } else {
                        // 刷新失败，清除token
                        tokenManager.clearTokens()
                    }
                }
            }
            
            response
        }
    }
    
    private fun createHeaderInterceptor(): Interceptor {
        return Interceptor { chain ->
            val originalRequest = chain.request()
            val newRequest = originalRequest.newBuilder()
                .header(ApiConfig.Headers.CONTENT_TYPE, "application/json")
                .header(ApiConfig.Headers.ACCEPT, "application/json")
                .header(ApiConfig.Headers.USER_AGENT, createUserAgent())
                .header(ApiConfig.Headers.DEVICE_ID, getDeviceId())
                .header(ApiConfig.Headers.APP_VERSION, BuildConfig.VERSION_NAME)
                .header(ApiConfig.Headers.PLATFORM, "android")
                .build()
            
            chain.proceed(newRequest)
        }
    }
    
    private fun createCacheInterceptor(): Interceptor {
        return Interceptor { chain ->
            var request = chain.request()
            
            // 离线时使用缓存
            if (!isNetworkAvailable()) {
                request = request.newBuilder()
                    .cacheControl(
                        CacheControl.Builder()
                            .maxStale(CacheConfig.CACHE_CONTROL_MAX_STALE, TimeUnit.SECONDS)
                            .build()
                    )
                    .build()
            }
            
            chain.proceed(request)
        }
    }
    
    private fun createNetworkCacheInterceptor(): Interceptor {
        return Interceptor { chain ->
            val response = chain.proceed(chain.request())
            
            // 在线时设置缓存
            if (isNetworkAvailable()) {
                response.newBuilder()
                    .header("Cache-Control", "public, max-age=${CacheConfig.CACHE_CONTROL_MAX_AGE}")
                    .removeHeader("Pragma")
                    .build()
            } else {
                response
            }
        }
    }
    
    private fun createRetryInterceptor(): Interceptor {
        return Interceptor { chain ->
            var response: Response? = null
            var exception: Exception? = null
            
            repeat(NetworkConfig.MAX_RETRY_COUNT) { attempt ->
                try {
                    response?.close()
                    response = chain.proceed(chain.request())
                    
                    if (response!!.isSuccessful) {
                        return@Interceptor response!!
                    }
                    
                    // 对于服务器错误进行重试
                    if (response!!.code >= 500 && attempt < NetworkConfig.MAX_RETRY_COUNT - 1) {
                        Thread.sleep(NetworkConfig.RETRY_DELAY * (attempt + 1))
                    } else {
                        return@Interceptor response!!
                    }
                } catch (e: Exception) {
                    exception = e
                    if (attempt < NetworkConfig.MAX_RETRY_COUNT - 1) {
                        Thread.sleep(NetworkConfig.RETRY_DELAY * (attempt + 1))
                    }
                }
            }
            
            response ?: throw exception ?: RuntimeException("Unknown error")
        }
    }
    
    private fun createLoggingInterceptor(): HttpLoggingInterceptor {
        return HttpLoggingInterceptor().apply {
            level = HttpLoggingInterceptor.Level.BODY
        }
    }
    
    private fun createUserAgent(): String {
        return "LaundryHelp/${BuildConfig.VERSION_NAME} (Android ${android.os.Build.VERSION.RELEASE}; ${android.os.Build.MODEL})"
    }
    
    private fun getDeviceId(): String {
        return android.provider.Settings.Secure.getString(
            context.contentResolver,
            android.provider.Settings.Secure.ANDROID_ID
        ) ?: "unknown"
    }
    
    private fun isNetworkAvailable(): Boolean {
        val connectivityManager = context.getSystemService(Context.CONNECTIVITY_SERVICE) as android.net.ConnectivityManager
        val activeNetwork = connectivityManager.activeNetwork ?: return false
        val networkCapabilities = connectivityManager.getNetworkCapabilities(activeNetwork) ?: return false
        return networkCapabilities.hasCapability(android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET)
    }
    
    private fun refreshTokenSync(refreshToken: String): TokenResponse? {
        return try {
            val refreshRequest = RefreshTokenRequest(refreshToken)
            val response = retrofit.create(ApiService::class.java)
                .refreshToken(refreshRequest)
                .execute()
            
            if (response.isSuccessful) {
                response.body()?.data
            } else {
                null
            }
        } catch (e: Exception) {
            null
        }
    }
}

// Token管理器
@Singleton
class TokenManager @Inject constructor(
    private val context: Context
) {
    private val prefs = context.getSharedPreferences("auth_prefs", Context.MODE_PRIVATE)
    
    companion object {
        private const val KEY_ACCESS_TOKEN = "access_token"
        private const val KEY_REFRESH_TOKEN = "refresh_token"
        private const val KEY_TOKEN_EXPIRES_AT = "token_expires_at"
    }
    
    fun saveTokens(accessToken: String, refreshToken: String, expiresIn: Long = 3600) {
        val expiresAt = System.currentTimeMillis() + (expiresIn * 1000)
        prefs.edit()
            .putString(KEY_ACCESS_TOKEN, accessToken)
            .putString(KEY_REFRESH_TOKEN, refreshToken)
            .putLong(KEY_TOKEN_EXPIRES_AT, expiresAt)
            .apply()
    }
    
    fun getAccessToken(): String? {
        val token = prefs.getString(KEY_ACCESS_TOKEN, null)
        val expiresAt = prefs.getLong(KEY_TOKEN_EXPIRES_AT, 0)
        
        return if (token != null && System.currentTimeMillis() < expiresAt) {
            token
        } else {
            null
        }
    }
    
    fun getRefreshToken(): String? {
        return prefs.getString(KEY_REFRESH_TOKEN, null)
    }
    
    fun clearTokens() {
        prefs.edit()
            .remove(KEY_ACCESS_TOKEN)
            .remove(KEY_REFRESH_TOKEN)
            .remove(KEY_TOKEN_EXPIRES_AT)
            .apply()
    }
    
    fun isLoggedIn(): Boolean {
        return getAccessToken() != null
    }
}

// 网络状态监听器
class NetworkStateListener @Inject constructor(
    private val context: Context
) {
    private val connectivityManager = context.getSystemService(Context.CONNECTIVITY_SERVICE) as android.net.ConnectivityManager
    private val networkCallbacks = mutableListOf<(Boolean) -> Unit>()
    
    private val networkCallback = object : android.net.ConnectivityManager.NetworkCallback() {
        override fun onAvailable(network: android.net.Network) {
            networkCallbacks.forEach { it(true) }
        }
        
        override fun onLost(network: android.net.Network) {
            networkCallbacks.forEach { it(false) }
        }
    }
    
    fun startListening() {
        val request = android.net.NetworkRequest.Builder()
            .addCapability(android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET)
            .build()
        connectivityManager.registerNetworkCallback(request, networkCallback)
    }
    
    fun stopListening() {
        connectivityManager.unregisterNetworkCallback(networkCallback)
    }
    
    fun addCallback(callback: (Boolean) -> Unit) {
        networkCallbacks.add(callback)
    }
    
    fun removeCallback(callback: (Boolean) -> Unit) {
        networkCallbacks.remove(callback)
    }
    
    fun isNetworkAvailable(): Boolean {
        val activeNetwork = connectivityManager.activeNetwork ?: return false
        val networkCapabilities = connectivityManager.getNetworkCapabilities(activeNetwork) ?: return false
        return networkCapabilities.hasCapability(android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET)
    }
}
